//-------------------------------------------------------------------------------------
//
// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows.
//
// Licensed under the BSD license, see LICENSE in JGE root for details.
// 
// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) <jhkhui@gmail.com>
// 
//-------------------------------------------------------------------------------------

#ifndef _JANIMATOR_H_
#define _JANIMATOR_H_

#include <vector>

#include "JRenderer.h"

using namespace std;


class JResourceManager;
class JQuad;
class JAnimatorFrame;
class JAnimatorObject;


//////////////////////////////////////////////////////////////////////////
/// A frame based animation system. The animation frames and play sequence
/// are loaded from a XML file.
///
/// A sample animation script:
///
/// @code
///	<?xml version="1.0" standalone="no" ?>
///
///	<script name="abc" type="ANIMATION_TYPE_ONCE_AND_STAY" framerate="20">
/// @endcode
/// 
/// "type" can be ANIMATION_TYPE_LOOPING, ANIMATION_TYPE_ONCE_AND_STAY, 
///	ANIMATION_TYPE_ONCE_AND_BACK, ANIMATION_TYPE_ONCE_AND_GONE or
///	ANIMATION_TYPE_PINGPONG
/// 
/// "framerate" is the rate of playback in frames per seconds.
/// 
/// @code
///	<frame id="1">
///		<obj name="head">
///			<settings quad="head" x="10" y="10" hsize="1.0" vsize="1.0" rotation="0.0" r="255" g="255" b="255" a="255" />
///		</obj>
///		<obj name="body">
///			<settings quad="body" />
///		</obj>
///	</frame>
/// @endcode
/// 
/// Each frame contains one or more frame objects. Each object is a quad with various
/// settings. "quad" is the name of the quad. "x" and "y" is the position. "hsize" is
/// the horizontal scaling and "vsize" is the vertical scaling. "rotation" is the angle
/// that the quad will be rotated in radians. You can also specify the color and alpha
/// of the quad with the "r", "g", "b" and "a" parameters.
/// 
/// @code
///	<frame id="2" time="0.20">
///		<obj name="head">
///			<settings quad="head" x="10" y="10" hsize="1.0" vsize="1.0" rotation="0.0" r="255" g="255" b="255" a="255" />
///		</obj>
///		<obj name="body">
///			<settings quad="body" a="128" />
///		</obj>
///	</frame>
///
///	
/// </script>
/// @endcode
///
/// A frame can also overide the global frame rate by using the "time" parameter (in second)
/// as shown above.
/// 
//////////////////////////////////////////////////////////////////////////
class JAnimator
{
public:

	//////////////////////////////////////////////////////////////////////////
	/// Constructor.
	/// 
	/// @param resourceMgr - ResourceManager to look for images (JQuads)
	/// 
	//////////////////////////////////////////////////////////////////////////
	JAnimator(JResourceManager* resourceMgr);

	//////////////////////////////////////////////////////////////////////////
	/// Destructor.
	/// 
	//////////////////////////////////////////////////////////////////////////
	~JAnimator();

	//////////////////////////////////////////////////////////////////////////
	/// Load animation sequence from a script file.
	/// 
	/// @param scriptFile - Animation script.
	/// 
	/// @return True if no problem during loading. False otherwise.
	/// 
	//////////////////////////////////////////////////////////////////////////
	bool Load(const char* scriptFile);

	//////////////////////////////////////////////////////////////////////////
	/// Start animation.
	///
	//////////////////////////////////////////////////////////////////////////
	void Start();

	//////////////////////////////////////////////////////////////////////////
	/// Stop animation.
	///
	//////////////////////////////////////////////////////////////////////////
	void Stop();

	//////////////////////////////////////////////////////////////////////////
	/// Pause animation.
	///
	//////////////////////////////////////////////////////////////////////////
	void Pause();

	//////////////////////////////////////////////////////////////////////////
	/// Resume animation.
	///
	//////////////////////////////////////////////////////////////////////////
	void Resume();

	//////////////////////////////////////////////////////////////////////////
	/// Update animation.
	///
	/// @param dt - Time elapsed since last update (in second).
	/// 
	//////////////////////////////////////////////////////////////////////////
	void Update(float dt);

	//////////////////////////////////////////////////////////////////////////
	/// Render animation.
	///
	//////////////////////////////////////////////////////////////////////////
	void Render();

	//////////////////////////////////////////////////////////////////////////
	/// Check if animation is playing or not.
	///
	/// @return True if playing animation.
	/// 
	//////////////////////////////////////////////////////////////////////////
	bool IsAnimating();

	//////////////////////////////////////////////////////////////////////////
	/// Check if the animation is active.
	/// 
	/// @return True if active.
	/// 
	//////////////////////////////////////////////////////////////////////////
	bool IsActive();

	JResourceManager* GetResourceManager();

	//////////////////////////////////////////////////////////////////////////
	/// Set current frame to a particular index.
	/// 
	/// @param index - The new index of current frame.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetCurrentFrameIndex(int index);

	//////////////////////////////////////////////////////////////////////////
	/// Get index of current frame.
	/// 
	/// @return Index of current frame.
	/// 
	//////////////////////////////////////////////////////////////////////////
	int GetCurrentFrameIndex();

	//////////////////////////////////////////////////////////////////////////
	/// Set animation type.
	/// 
	/// @param type - Animation type.
	/// 
	/// @code
	///		JSprite::ANIMATION_TYPE_LOOPING - Default
	///		JSprite::ANIMATION_TYPE_ONCE_AND_GONE
	///		JSprite::ANIMATION_TYPE_ONCE_AND_STAY
	///		JSprite::ANIMATION_TYPE_ONCE_AND_BACK
	///		JSprite::ANIMATION_TYPE_PINGPONG
	/// @endcode
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetAnimationType(int type);

	//////////////////////////////////////////////////////////////////////////
	/// Set position of the sprite.
	/// 
	/// @param x - X position.
	/// @param y - Y position.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetPosition(float x, float y);

	//////////////////////////////////////////////////////////////////////////
	/// Set anchor point of the animation. All rendering operations will be
	/// based on this anchor point.
	/// 
	/// @param x - X position of the anchor point.
	/// @param y - Y position of the anchor point.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetHotSpot(float x, float y);

private:
	JResourceManager* mResource;
	vector<JAnimatorFrame *> mFrames;

	bool mAnimating;
	bool mActive;
	int mCurrentFrame;
	int mAnimationType;
	int mFrameDelta;

	float mX;
	float mY;
	float mHotSpotX;
	float mHotSpotY;


};


//////////////////////////////////////////////////////////////////////////
/// A single frame of an animation.
/// 
//////////////////////////////////////////////////////////////////////////
class JAnimatorFrame
{
public:
	//////////////////////////////////////////////////////////////////////////
	/// Constructor.
	/// 
	/// @param parent - Parent of the frame.
	/// 
	//////////////////////////////////////////////////////////////////////////
	JAnimatorFrame(JAnimator* parent);

	//////////////////////////////////////////////////////////////////////////
	/// Destructor.
	/// 
	//////////////////////////////////////////////////////////////////////////
	~JAnimatorFrame();

	//////////////////////////////////////////////////////////////////////////
	/// Add a new object into the frame.
	/// 
	/// @param obj - New animation object.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void AddObject(JAnimatorObject *obj);

	//////////////////////////////////////////////////////////////////////////
	/// Set play time of the frame.
	/// 
	/// @param duration - Time to play (in second).
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetFrameTime(float duration);

	//////////////////////////////////////////////////////////////////////////
	/// Frame update.
	///
	/// @param dt - Time elapsed since last update (in second).
	/// 
	/// @return True if the frame is done.
	/// 
	//////////////////////////////////////////////////////////////////////////
	bool Update(float dt);

	//////////////////////////////////////////////////////////////////////////
	/// Render frame.
	/// 
	/// @param x - X position for rendering.
	/// @param y - Y position for rendering.
	///
	//////////////////////////////////////////////////////////////////////////
	void Render(float x, float y);

	//////////////////////////////////////////////////////////////////////////
	/// Start playing the frame.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void Start();


private:
	float mTimer;
	float mFrameTime;
	JAnimator* mAnimator;
	vector<JAnimatorObject *> mObjects;

};


//////////////////////////////////////////////////////////////////////////
/// Animation object (image quad) in a frame.
/// 
//////////////////////////////////////////////////////////////////////////
class JAnimatorObject
{
public:

	//////////////////////////////////////////////////////////////////////////
	/// Constructor.
	/// 
	//////////////////////////////////////////////////////////////////////////
	JAnimatorObject();

	//////////////////////////////////////////////////////////////////////////
	/// Destructor.
	/// 
	//////////////////////////////////////////////////////////////////////////
	~JAnimatorObject();

	//////////////////////////////////////////////////////////////////////////
	/// Update object.
	///
	/// @param dt - Time elapsed since last update (in second).
	/// 
	//////////////////////////////////////////////////////////////////////////
	void Update(float dt);

	//////////////////////////////////////////////////////////////////////////
	/// Render object.
	/// 
	/// @param x - X position for rendering.
	/// @param y - Y position for rendering.
	///
	//////////////////////////////////////////////////////////////////////////
	void Render(float x, float y);

	//////////////////////////////////////////////////////////////////////////
	/// Set something to show.
	///
	/// @param quad - Image quad.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetQuad(JQuad *quad);

	//////////////////////////////////////////////////////////////////////////
	/// Set position of the object.
	/// 
	/// @param x - X position.
	/// @param y - Y position.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetPosition(float x, float y);

	//////////////////////////////////////////////////////////////////////////
	/// Set rotation factor of the object.
	/// 
	/// @param angle - Rotation angle in radian.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetRotation(float angle);

	//////////////////////////////////////////////////////////////////////////
	/// Set horizontal scale of the object.
	/// 
	/// @param scale - Horizontal scale.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetHScale(float scale);

	//////////////////////////////////////////////////////////////////////////
	/// Set vertical scale of the object.
	/// 
	/// @param scale - Vertical scale.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetVScale(float scale);

	//////////////////////////////////////////////////////////////////////////
	/// Set blending color of the object.
	/// 
	/// @param color - Blending color.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetColor(PIXEL_TYPE color);

	//////////////////////////////////////////////////////////////////////////
	/// Set horizontal flipping.
	/// 
	/// @param flag - flipping flag.
	/// 
	//////////////////////////////////////////////////////////////////////////
	void SetFlip(bool flag);

private:
	JRenderer* mRenderer;
	JQuad* mQuad;

	float mX;
	float mY;
	float mRotation;
	float mHScale;
	float mVScale;
	PIXEL_TYPE mColor;
	bool mFlipped;
};

#endif

